
package sw6.visualschedule.activitylist;

import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import sw6.girafAppKit.GirafActivity;
import sw6.lib.Settings;
import sw6.visualschedule.Countdown;
import sw6.visualschedule.R;
import sw6.visualschedule.StepList;
import sw6.visualschedule.entities.ActivityStatus;
import sw6.visualschedule.entities.ActivityStatusType;
import sw6.visualschedule.entities.ScheduleActivity;
import sw6.visualschedule.extendedViews.DisableableScrollView;
import sw6.visualschedule.extendedViews.LinkedActivityView;
import sw6.visualschedule.persistence.ActivityStatusRepo;
import sw6.visualschedule.persistence.ScheduleActivityRepo;
import tools.BundleHelper;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class VisualSchedule extends GirafActivity {

    private static final String LOG_NAME = "ActivityList";
    

    final private static int STEPS_LIST_RESULT = 0; //Value returned by Step List on successfully finished StepList    

    //Contains all activities for "today"
    private transient List<ScheduleActivity> mActivities;    
    private transient ScheduleActivityRepo mActivityService;
    private transient ActivityStatusRepo mActivityStatusService;
    //Background pattern/color is applied to this view at runtime
    private transient LinearLayout mBackgroundImageView;
    //VisualSchedule context.
    private Context mContext;
    /*When dropped on target (is started) an activity is stored in this variable.     
     *The variable is read when activity is resumed, when returning from steps-view.*/
    private transient LinkedActivityView mCurrentActivity;
    //Contains all finished activities (right lane)
    private transient LinearLayout mFinishedActivitiesView;    
    //Contains all unfinished activities (left lane)
    private transient LinearLayout mNewActivitiesView;
    private transient FrameLayout mOuterContainerView;
    /*The scroll-functionality is disabled when dragging an activity.
     *Additionally, DraggingImages (the one under the user's finger) are added
     *and removed from this view*/
    private transient DisableableScrollView mScrollView;    
    //The LinearLayout in the drawer containing the spontaneous activities.
    private transient LinearLayout mSpontanousView;    
    private transient int mThumbnailMaxHeight;    
    private transient int mThumbnailMaxWidth;

    /**
     * Adds an activity to the screen. Depending on the status of the activity, it will be placed in the
     * left or right lane.
     * 
     * @param activity the activity to add. Must contain runtime information (status and date)
     * @param position in the list.
     */
    private void addActivity(ScheduleActivity activity, int position) {
        final Bitmap bitmap = activity.getImageBitmapThumbnail(mContext, mThumbnailMaxWidth, mThumbnailMaxHeight);
        
        //Create left image view
    	final LinkedActivityView imgLeft = new LinkedActivityView(mContext, activity, bitmap, Settings.getUserProfile(mContext).canRead());
    	imgLeft.setId(position);
    	imgLeft.setDrawingCacheEnabled(true);
    	imgLeft.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    	
        LinearLayout v = new LinearLayout(mContext);
        v.setMinimumHeight(40);
        v.setVisibility(View.INVISIBLE);
        
        mNewActivitiesView.addView(imgLeft);
        mNewActivitiesView.addView(v);
    	
        //Create right image view
    	final LinkedActivityView imgRight;
    	
        LinearLayout v2 = new LinearLayout(mContext);
        v2.setMinimumHeight(40);
        v2.setVisibility(View.INVISIBLE);
    	mFinishedActivitiesView.addView(v2);
   	
    	if (activity.getInstanceStatus() == ActivityStatusType.FINISHED) {
    	    imgLeft.setVisibility(View.INVISIBLE);
    		imgRight = new LinkedActivityView(mContext, activity, bitmap, Settings.getUserProfile(mContext).canRead());
		}
    	else {
    		imgRight = new LinkedActivityView(mContext, activity, bitmap, Settings.getUserProfile(mContext).canRead(), true);
    		imgRight.setVisibility(View.INVISIBLE);
    	 
    	    //Should left image also be animated?
    	    if (activity.getInstanceDate().before(new Date())) {
    	    	imgLeft.startAnimation();
    	    }
    	}
    	
    	imgRight.setId(position);
    	imgRight.setDrawingCacheEnabled(true);
    	imgRight.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    	mFinishedActivitiesView.addView(imgRight);
    	
        //Link image views together
        imgLeft.setLinkedImageView(imgRight);
        imgRight.setLinkedImageView(imgLeft);
        
        /**
         * A known android bug makes getDrawingCache return null for "composite views" if it has not been
         * actually drawn on screen. The following makes it possible to build a drawingcache by manually
         * setting the dimensions of the view (that it already knows :P)
         */
        imgLeft.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        imgLeft.layout(0, 0, imgLeft.getMeasuredWidth(), imgLeft.getMeasuredHeight()); 
        imgLeft.setDrawingCacheEnabled(true);
        imgLeft.buildDrawingCache(true);
        
        //Add draggable image and its activity listener
        final ImageView draggableImage = new ImageView(mContext);
        
        if (imgLeft.isDrawingCacheEnabled()) {
        	draggableImage.setImageBitmap(imgLeft.getDrawingCache() );
        }
        else {
        	draggableImage.setImageDrawable(getResources().getDrawable(R.drawable.icon));
        }
        
        ActivityImageViewTouchListener draggableTouchListener = new ActivityImageViewTouchListener(mContext, imgLeft, draggableImage);
        draggableTouchListener.setActivityListener(new StartActivityListener() {	
			
			@Override
			public void down() {}
			
			@Override
			public void draggableImageAwayFromTarget() {
				imgRight.setBackgroundDrawable(getResources().getDrawable(R.drawable.my_border_transparent));
			}
			
			@Override
			public void draggableImageDroppedOnTarget() {
				mCurrentActivity = imgLeft;
				
				if (mCurrentActivity.getScheduleActivity().getInstanceDate().before(new Date())) {
            		//Activity "available". Show step list
					mOuterContainerView.removeView(draggableImage);
					
					startStepsList(imgLeft.getScheduleActivity());	
            	} else {
            		//It's not time for the activity yet.
            		showCountdown();
            		imgLeft.setVisibility(View.VISIBLE);
            		draggableImage.setVisibility(View.INVISIBLE);
            		imgLeft.getLinkedImageView().setVisibility(View.INVISIBLE);
            	}
			}
			
			@Override
			public void draggableImageOverTarget() {
				imgRight.setBackgroundDrawable(getResources().getDrawable(R.drawable.my_border));
			}

			@Override
			public void up() {
				mScrollView.setAllowedToScroll(true);
			}
		});
        draggableImage.setOnTouchListener(draggableTouchListener);        
        draggableImage.setVisibility(View.INVISIBLE);
        draggableImage.setMinimumWidth(50);
        draggableImage.setMinimumHeight(50);        
        mOuterContainerView.addView(draggableImage, new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT));
        	mOuterContainerView.setVisibility(View.VISIBLE);
        
        	imgLeft.setOnTouchListener(new OnTouchListener() {
			
			@Override
			public boolean onTouch(View v, MotionEvent event) {			
				switch (event.getActionMasked()) {
				case MotionEvent.ACTION_DOWN:
					mScrollView.setAllowedToScroll(false);
					draggableImage.setVisibility(View.VISIBLE);
					imgLeft.stopAnimation();
					imgLeft.setVisibility(View.INVISIBLE);
					return draggableImage.dispatchTouchEvent(event);
				case MotionEvent.ACTION_UP:				
					mScrollView.setAllowedToScroll(true);
									
					return draggableImage.dispatchTouchEvent(event);
				case MotionEvent.ACTION_MOVE:				
					return draggableImage.dispatchTouchEvent(event);
				default:
					break;
				}
				return false;
			}
		});
    }

    /**
     * Called when returning from Step View (either because activities is done, or used pressed back)
     */
    @Override
    protected final void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (requestCode == STEPS_LIST_RESULT) {
            if (resultCode == RESULT_OK) {
                final ActivityStatus status = new ActivityStatus(mCurrentActivity.getScheduleActivity(), mCurrentActivity.getScheduleActivity().getInstanceDate());
                status.setStatus(ActivityStatusType.FINISHED);
                mActivityStatusService.insertOrUpdate(status);
            }
            mCurrentActivity = null;
        }
    }
    
    @Override
    public void onCreate(final Bundle savedInstanceState) {   
    	super.onCreate(savedInstanceState);
        
        setContentView(R.layout.activitylist);
        
        mContext = getApplicationContext();
        
        //Locate views in layout, so they can be modified at runtime throughout the class.
        
        mScrollView = (DisableableScrollView) findViewById(R.id.ActivityListScrollView);
        mOuterContainerView = (FrameLayout) findViewById(R.id.outerContainer);        
        mNewActivitiesView = (LinearLayout) findViewById(R.id.newActivities);
        mFinishedActivitiesView = (LinearLayout) findViewById(R.id.finishedActivities);
        mBackgroundImageView= (LinearLayout) findViewById(R.id.container);
        mSpontanousView = (LinearLayout) findViewById(R.id.spontanousList);
        
        final Display display = getWindowManager().getDefaultDisplay();
        mThumbnailMaxWidth = display.getWidth() / 3;
        mThumbnailMaxHeight = display.getHeight() / 2;
        
        //Create persistent database helper instances
        mActivityService = new ScheduleActivityRepo(mContext);
        mActivityStatusService = new ActivityStatusRepo(mContext);

        //Define what Intent opens when pressing "secret admin combo (UP -> DOWN * 3)"
        Intent adminIntent = new Intent();
        adminIntent.setComponent(new ComponentName("sw6.admin", "sw6.admin.MainActivity"));
        adminIntent.putExtra("packageName", "sw6.visualschedule");
        setParentIntent(adminIntent);
    }
    
    @Override
    protected void onPause() {        
    	//Stop animations and release memory used by bitmaps
    	
    	LinkedActivityView child;        
    	for (int i = 0; i < mNewActivitiesView.getChildCount(); i++) {
    	    if (mNewActivitiesView.getChildAt(i) instanceof LinkedActivityView) {
            	child = (LinkedActivityView)mNewActivitiesView.getChildAt(i);
            	child.clearAnimation();
            	child.unbindDrawables();
            	child.destroyDrawingCache();
            	child = null;
    	    }
        }
    	
    	for (int i = 0; i < mFinishedActivitiesView.getChildCount(); i++)
    	{
    	    if (mFinishedActivitiesView.getChildAt(i) instanceof LinkedActivityView) {
        	    child = (LinkedActivityView)mFinishedActivitiesView.getChildAt(i);
        	    child.clearAnimation();
        	    child.unbindDrawables();
        	    child.destroyDrawingCache();
        	    child = null;
    	    }
    	}
    	
    	//DebugHelper.logHeap(this.getClass());
    	
    	super.onPause();
    }
    
    @Override
    protected void onResume() {
        super.onResume();        
        
        mContext = getApplicationContext();
        
        switch ((int)Settings.getEnum(mContext, "Background")) {
		case 0:
			mBackgroundImageView.setBackgroundColor(Color.BLACK);			
			break;
		case 1:
			mBackgroundImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.skystyle));
			break;
		case 2:
			mBackgroundImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.grassstyle));
			break;
		case 3:
			mBackgroundImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.woodstyle));
			break;
		case 4:
			mBackgroundImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.doggystyle));
			break;
		case 5:
			mBackgroundImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.brickstyle));
			break;
		default:
			mBackgroundImageView.setBackgroundColor(Color.BLACK);
			break;
		}
        
        populateData();
        populateSpontanousList();
        
        //DebugHelper.logHeap(this.getClass());
    }
    
    /**
     * Adds activities with status (date and status) to screen.
     */
    private void populateData() {
    	if (mFinishedActivitiesView.getChildCount() > 0)
    		mFinishedActivitiesView.removeAllViews();
    	if (mNewActivitiesView.getChildCount() > 0)
    		mNewActivitiesView.removeAllViews();
        
        /*
         * Loading images may take a long time if they're really large.
         * Create placeholder images, and then start a thread that populates
         * these with proper images. 
         * 
         * TODO: Take a look at http://developer.android.com/guide/topics/resources/runtime-changes.html
         */
        
        mActivities = mActivityService.getActivities(GregorianCalendar.getInstance().getTime());

        for (int i = 0; i < mActivities.size(); i++) {
        	//TODO: Create model-getter that fetches all but disabled activities.
        	if (mActivities.get(i).getInstanceStatus() != ActivityStatusType.DISABLED)
        		addActivity(mActivities.get(i), i);
        }
    }
    
    /**
     * Adds all spontaneous activities to slide-out drawer. 
     */
    private void populateSpontanousList() {
        if (mSpontanousView.getChildCount() > 0)
        	mSpontanousView.removeAllViews();
        
        List<ScheduleActivity> spontanousActivities = mActivityService.getSpontaneousActivities();
        LinkedActivityView activityView;
        for (final ScheduleActivity scheduleActivity : spontanousActivities) {
        	activityView = new LinkedActivityView(getApplicationContext(), scheduleActivity, scheduleActivity.getImageBitmapThumbnail(getApplicationContext(), 200, 200), true);        	
        	//imgView = new ImageView(getApplicationContext());
        	//imgView.setImageBitmap(scheduleActivity.getImageBitmapThumbnail(getApplicationContext(), 200, 200));
       		activityView.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					Intent intent = new Intent().setClass(getApplicationContext(), StepList.class);
			        intent.putExtra(BundleHelper.ACTIVITY_ID, scheduleActivity.getId());
			        startActivity(intent);
				}
       		});
       		mSpontanousView.addView(activityView);       		       		
       		
       		LinearLayout v = new LinearLayout(mContext);
            v.setMinimumHeight(20);
            v.setVisibility(View.INVISIBLE);
		}
    }
    
    //Called when dropping an activity on dropzone, and it's not time for it yet
    private void showCountdown() {
    	Log.d(LOG_NAME,"showCountdown");
    	final Date date = mCurrentActivity.getScheduleActivity().getInstanceDate();
    	
    	final long milliseconds = (date.getTime() - new Date().getTime()); 
    	
    	final Countdown countdownDialog = new Countdown(this, Countdown.CLOCKCOUNTDOWN, milliseconds);
    	countdownDialog.show();
    }
        
    private void startStepsList(final ScheduleActivity activity) {
    	final ActivityStatus status = new ActivityStatus(activity, activity.getInstanceDate());
        status.setStatus(ActivityStatusType.SKIPPED);
        mActivityStatusService.insertOrUpdate(status);
        
        final Intent intent = new Intent().setClass(mContext, StepList.class);
        intent.putExtra(BundleHelper.ACTIVITY_ID, activity.getId() );        
        startActivityForResult(intent, STEPS_LIST_RESULT);
    }    
    
}
